package post

import (
	"context"
	// "fmt"
	"strconv"
	"strings"

	"mall/common/globalkey"
	"mall/common/jwt"
	"mall/common/utils/pointy"
	"mall/service/backend/rpc/backendclient"
	"mall/service/blog/rpc/blogclient"
	"mall/service/forum/api/internal/logic/util"
	"mall/service/forum/api/internal/svc"
	"mall/service/forum/api/internal/types"
	"mall/service/forum/api/internal/utils/parse"
	"mall/service/forum/rpc/forumclient"

	// "github.com/sirupsen/logrus"
	"github.com/zeromicro/go-zero/core/logx"
)

type GetReviewListLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewGetReviewListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetReviewListLogic {
	return &GetReviewListLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *GetReviewListLogic) GetReviewList(
	req *types.GetReviewListReq,
	headers *[]*types.Header,
) (*types.GetReviewListResp, error) {
	userId := jwt.GetUserId(l.ctx)

	page, pageSize := parse.ParsePageInfo(
		req.Current,
		req.PageSize,
		l.svcCtx.Config.Query.DefaultAmount,
		l.svcCtx.Config.Query.MaxAmount,
	)

	platformId := globalkey.ThirdPartyPlatformWechatMini
	if req.Type != nil && *req.Type == 1 {
		return l.getSectionReviewList(headers, page, pageSize, userId, platformId)
	}

	return l.getReviewList(req.Type, page, pageSize, userId, platformId)
}

func (l *GetReviewListLogic) getSectionReviewList(
	headers *[]*types.Header,
	page uint64,
	pageSize uint64,
	userId uint64,
	platformId uint32,
) (resp *types.GetReviewListResp, err error) {
	preload := "sectionPost:SectionId,PostId"
	eagerLoad := "sectionPost:section"
	preload += ";section:Id,Title,Subtitle,PicUrl"
	preFilterEntity := "section"

	var filters []string
	filters = append(filters, "PostType,equalTo:"+strconv.FormatInt(int64(globalkey.SettingSectionTypeForumPostIndex), 10))
	var preFilters []string
	preFilters = append(preFilters, "Status,equalTo:"+strconv.FormatInt(int64(globalkey.StatusApproved), 10))
	preFilters = append(preFilters, "Type,equalTo:"+strconv.FormatInt(int64(globalkey.SettingSectionTypeForumPostIndex), 10))
	res, err := l.svcCtx.BackendRpc.GetSectionPostList(l.ctx, &backendclient.BaseListReq{
		Offset:          uint32((page - 1) * pageSize),
		Limit:           uint32(pageSize),
		Preload:         pointy.GetPointer(preload),
		EagerLoad:       pointy.GetPointer(eagerLoad),
		Filter:          pointy.GetPointer(strings.Join(filters, ";")),
		PreFilterEntity: pointy.GetPointer(preFilterEntity),
		PreFilter:       pointy.GetPointer(strings.Join(preFilters, ";")),
		VisitorId:       pointy.GetPointer(userId),
		PlatformId:      pointy.GetPointer(platformId),
	})
	if err != nil {
		return nil, err
	}

	var hasNextPage bool
	var hasPreviousPage bool
	if res.HasNextPage != nil && *res.HasNextPage > 0 {
		hasNextPage = true
	}
	if res.HasPreviousPage != nil && *res.HasPreviousPage > 0 {
		hasPreviousPage = true
	}

	resp = &types.GetReviewListResp{
		BaseListInfo: types.BaseListInfo{
			HasNextPage:     hasNextPage,
			HasPreviousPage: hasPreviousPage,
		},
	}

	if len(res.List) > 0 {
		var pids []string
		postIdMap := make(map[uint64]struct{})
		var section *backendclient.SectionInfo
		for _, v := range res.List {
			if v.PostId != nil && *v.PostId > 0 {
				pid := *v.PostId
				if _, ok := postIdMap[pid]; !ok {
					pids = append(pids, strconv.FormatUint(pid, 10))
					postIdMap[pid] = struct{}{}

					if section == nil && v.Section != nil {
						section = v.Section
					}
				}
			}
		}

		if len(pids) > 0 {
			reviews, err := l.getReviewListByIds(strings.Join(pids, ","))
			if err != nil {
				return nil, err
			}

			if len(reviews) > 0 {
				idReviewMap := make(map[uint64]*types.ReviewInfo)
				for _, review := range reviews {
					if review.Id != nil && *review.Id > 0 {
						idReviewMap[*review.Id] = review
					}
				}

				for pid := range postIdMap {
					if review, ok := idReviewMap[pid]; ok {
						resp.List = append(resp.List, review)
					}
				}
				if section != nil {
					resp.Section = &types.SectionInfo{
						Id:       section.Id,
						Title:    section.Title,
						Subtitle: section.Subtitle,
						ImageUrl: section.PicUrl,
					}
				}
			}
		}

		*headers = []*types.Header{
			{
				Key:   "x-class",
				Value: "com.djx.appview.MallForumPage",
			},
		}
	}

	return resp, nil
}

func (l *GetReviewListLogic) getReviewListByIds(ids string) (resp []*types.ReviewInfo, err error) {
	preload := "forumPost:Id,Title,AuthorId,AuthorName,AuthorAvatar,AuthorRankId,AuthorRoleId,Sticky"
	eagerLoad := "forumPost:forumPostMeta"
	preload += ";forumPostMeta:mediaUrl"

	var filters []string
	filters = append(filters, "Status,equalTo:"+strconv.FormatInt(int64(globalkey.StatusApproved), 10))
	filters = append(filters, "ForumId,equalTo:"+strconv.FormatInt(l.svcCtx.Config.Query.ColumnForumId, 10))
	filters = append(filters, "Id,in:"+ids)

	res, err := l.svcCtx.ForumRpc.GetPostList(l.ctx, &forumclient.BaseListReq{
		Preload:   pointy.GetPointer(preload),
		EagerLoad: pointy.GetPointer(eagerLoad),
		Filter:    pointy.GetPointer(strings.Join(filters, ";")),
	})
	if err != nil {
		return nil, err
	}

	if len(res.List) > 0 {
		for _, v := range res.List {
			var mediaUrl *string
			if len(v.Meta) > 0 {
				for _, m := range v.Meta {
					if m.Key == nil || m.Value == nil {
						continue
					}

					val := *m.Value
					switch *m.Key {
					case "mediaUrl":
						mediaUrl = pointy.GetPointer(val)
					}
				}
			}

			resp = append(resp, &types.ReviewInfo{
				Id:             v.Id,
				Title:          v.PostTitle,
				AuthorId:       v.AuthorId,
				AuthorNickname: v.AuthorNickname,
				AuthorAvatar:   v.AuthorAvatar,
				AuthorRankId:   v.AuthorRankId,
				AuthorRoleId:   v.AuthorRoleId,
				Sticky:         v.Sticky,
				ImageUrl:       mediaUrl,
			})
		}
	}

	return resp, nil
}

func (l *GetReviewListLogic) getReviewList(
	postType *uint32,
	page uint64,
	pageSize uint64,
	userId uint64,
	platformId uint32,
) (resp *types.GetReviewListResp, err error) {
	preload := "forumPost:Id,Title,PublicDate,Sticky"
	eagerLoad := "forumPost:forumPostMeta"
	var filters []string
	var withParent bool
	var withMedia bool
	if postType != nil {
		if *postType == 2 { // 查询后台香评列表
			filters = append(filters, "ForumId,equalTo:"+strconv.FormatInt(l.svcCtx.Config.Query.ColumnForumId, 10))
			filters = append(filters, "Status,equalTo:"+strconv.FormatInt(int64(globalkey.StatusApproved), 10))
			preload += ",AuthorId,AuthorName,AuthorAvatar,AuthorRankId,AuthorRoleId"
		} else if *postType == 3 { // 查询我的香评
			filters = append(filters, "ForumId,equalTo:"+strconv.FormatInt(l.svcCtx.Config.Query.PostForumId, 10))
			filters = append(filters, "AuthorId,equalTo:"+strconv.FormatUint(userId, 10))
			filters = append(filters, "Status,notEqualTo:"+strconv.FormatInt(int64(globalkey.StatusDeleted), 10))
			preload += ",ParentId,Status,ContentHtml;forumMedia:Id,Uid,Uri,Url,Order,Thumbnail"
			withParent = true
			withMedia = true
			eagerLoad += ",forumMedia"
		}
	}
	preload += ";forumPostMeta:mediaUrl"

	res, err := l.svcCtx.ForumRpc.GetPostList(l.ctx, &forumclient.BaseListReq{
		Offset:     uint32((page - 1) * pageSize),
		Limit:      uint32(pageSize),
		Preload:    pointy.GetPointer(preload),
		EagerLoad:  pointy.GetPointer(eagerLoad),
		Filter:     pointy.GetPointer(strings.Join(filters, ";")),
		VisitorId:  pointy.GetPointer(userId),
		PlatformId: pointy.GetPointer(platformId),
	})
	if err != nil {
		return nil, err
	}

	var hasNextPage bool
	var hasPreviousPage bool
	if res.HasNextPage != nil && *res.HasNextPage > 0 {
		hasNextPage = true
	}
	if res.HasPreviousPage != nil && *res.HasPreviousPage > 0 {
		hasPreviousPage = true
	}

	resp = &types.GetReviewListResp{
		BaseListInfo: types.BaseListInfo{
			HasNextPage:     hasNextPage,
			HasPreviousPage: hasPreviousPage,
		},
	}

	if len(res.List) > 0 {
		var parentMap map[uint64]*types.KbEntryInfo
		if withParent {
			var pids []string
			for _, v := range res.List {
				if v.ParentId != nil && *v.ParentId > 0 {
					pids = append(pids, strconv.FormatUint(*v.ParentId, 10))
				}
			}
			if len(pids) > 0 {
				parentMap, err = l.getParentMap(pids)
				if err != nil {
					return nil, err
				}
			}
		}
		for _, v := range res.List {
			var parent *types.KbEntryInfo
			if withParent && v.ParentId != nil && *v.ParentId > 0 && parentMap != nil {
				if pv, ok := parentMap[*v.ParentId]; ok {
					parent = pv
				}
			}

			var mediaUrl *string
			if len(v.Meta) > 0 {
				for _, m := range v.Meta {
					if m.Key == nil || m.Value == nil {
						continue
					}

					val := *m.Value
					switch *m.Key {
					case "mediaUrl":
						mediaUrl = pointy.GetPointer(val)
					}
				}
			}

			var media []*types.TmpMediaInfo
			if withMedia && len(v.Media) > 0 {
				for _, m := range v.Media {
					var url string
					if m.Url != nil && len(*m.Url) > 0 {
						url = *m.Url
					}
					if len(url) == 0 && m.Uri != nil && len(*m.Uri) > 0 {
						url = *m.Uri
					}

					media = append(media, &types.TmpMediaInfo{
						Uid:       m.Uid,
						Id:        m.Id,
						Thumbnail: m.Thumbnail,
						Order:     m.Order,
						Url:       pointy.GetPointer(url),
						AltText:   m.AltText,
					})
				}
			}

			var canEdit *uint32
			var canSubmit *uint32
			var statusText *string
			if withParent && v.Status != nil { // 我的香评
				if *v.Status != uint32(globalkey.StatusDeleted) && *v.Status != uint32(globalkey.StatusApproved) {
					canEdit = pointy.GetPointer(uint32(1))
				}
				if *v.Status == uint32(globalkey.StatusDraft) {
					canSubmit = pointy.GetPointer(uint32(1))
				}
				statusText = pointy.GetPointer(util.GetStatusTextNew(v.Status))
			}

			resp.List = append(resp.List, &types.ReviewInfo{
				Id:             v.Id,
				Title:          v.PostTitle,
				ContentHtml:    v.PostContent,
				AuthorId:       v.AuthorId,
				AuthorNickname: v.AuthorNickname,
				AuthorAvatar:   v.AuthorAvatar,
				AuthorRankId:   v.AuthorRankId,
				AuthorRoleId:   v.AuthorRoleId,
				ImageUrl:       mediaUrl,
				PublicDate:     v.PublicDate,
				CanEdit:        canEdit,
				CanSubmit:      canSubmit,
				StatusText:     statusText,
				Sticky:         v.Sticky,
				Parent:         parent,
				Media:          media,
			})
		}
	}

	return resp, nil
}

func (l *GetReviewListLogic) getParentMap(ids []string) (map[uint64]*types.KbEntryInfo, error) {
	if len(ids) == 0 {
		return nil, nil
	}

	preload := "blogBook:Id,Title,Slug;blogBookMeta:mediaUrl;blogMedia:Uri,Url"
	eagerLoad := "blogBook:blogBookMeta,blogMedia"
	var filters []string
	filters = append(filters, "Status,equalTo:"+strconv.FormatInt(int64(globalkey.PostStatusPublish), 10))
	filters = append(filters, "Id,in:"+strings.Join(ids, ","))

	res, err := l.svcCtx.BlogRpc.GetKBPostListTmp(l.ctx, &blogclient.BaseListReq{
		Preload:   pointy.GetPointer(preload),
		EagerLoad: pointy.GetPointer(eagerLoad),
		Filter:    pointy.GetPointer(strings.Join(filters, ";")),
	})
	if err != nil {
		logx.Infow("GetReviewList getParentMap BlogRpc.GetKBPostListTmp err", logx.Field("detail", err.Error()))
		return nil, err
	}

	if len(res.List) > 0 {
		resp := make(map[uint64]*types.KbEntryInfo)
		for _, v := range res.List {
			if v.Id == nil || *v.Id == 0 {
				continue
			}

			var mediaUrl *string
			if len(v.Meta) > 0 {
				for _, m := range v.Meta {
					if m.Key == nil || m.Value == nil {
						continue
					}

					val := *m.Value
					switch *m.Key {
					case "mediaUrl":
						mediaUrl = pointy.GetPointer(val)
					}
				}
			}

			// var media []*types.TmpMediaInfo
			if mediaUrl == nil && len(v.Media) > 0 {
				for _, m := range v.Media {
					var url string
					if m.Url != nil && len(*m.Url) > 0 {
						url = *m.Url
					}
					if len(url) == 0 && m.Uri != nil && len(*m.Uri) > 0 {
						url = *m.Uri
					}
					if len(url) > 0 {
						mediaUrl = pointy.GetPointer(url)
					}

					// media = append(media, &types.TmpMediaInfo{
					// 	Uid:       m.Uid,
					// 	Id:        m.Id,
					// 	Thumbnail: m.Thumbnail,
					// 	Order:     m.Order,
					// 	Url:       pointy.GetPointer(url),
					// 	AltText:   m.AltText,
					// })
				}
			}

			resp[*v.Id] = &types.KbEntryInfo{
				Id:       v.Id,
				Title:    v.Title,
				Slug:     v.Slug,
				ImageUrl: mediaUrl,
			}
		}

		return resp, nil
	}

	return nil, nil
}
